home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1991, Silicon Graphics, Inc.
- * All Rights Reserved.
- */
- /*
- * bufferglx: a GL-Xlib version of Yusuf Attarwala's Motif-based
- * "bufferglm.c" demo program. bufferglx implements a mixed
- * model methodology for switching back-and-forth between
- * single and double -buffer drawing modes.
- *
- * left mouse : switch to single buffer
- * middle mouse: switch to double buffer
- * right mouse : animate the green sphere in the current buffer mode
- *
- * the program handles redraw (ConfigureNotify--move and resize) and
- * expose (pop, expose, de-iconify) and button (i.e. mouse) events.
- * ESC key exits the program.
- *
- * Note the places where the XMapWindow/XUnmapWindow and Winset (a
- * wrapper to GLXwinset) routines are implemented.
- *
- * ratmandu -- November, 1991
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/keysym.h>
- #include <X11/Xos.h>
- #include <X11/Xatom.h>
- #include <X11/extensions/XI.h>
- #include <X11/extensions/XInput.h>
- #include <gl/glws.h>
- #include <gl.h>
- #include <gl/sphere.h>
-
- #define top 0
- #define SBglwin 1
- #define DBglwin 2
- #define WINMAX 3
-
- Display *dpy; /* The X server connection */
- Atom del_atom;
- Window wins[WINMAX];
-
-
- /* function declarations */
-
- static void openwindow(char *);
- void Winset(Window, int);
- static Window glx_create_window(Window, int, int, int, int, int, char*);
- static void resize_buffer(long);
- static void clean_exit();
- void initGL();
- void bindLight();
- void setMatrix();
- void loop();
- void drawScene();
-
-
- static float material1[] = {
- DIFFUSE, 0.6,0.2,0.2,
- SPECULAR, 1.0,1.0,1.0,
- SHININESS, 120.0,
- LMNULL
- };
-
- static float material2[] = {
- DIFFUSE, 0.2,0.8,0.2,
- SPECULAR, 1.0,1.0,1.0,
- SHININESS, 120.0,
- LMNULL
- };
-
- static float infinite[] = {
- AMBIENT, 0.3,0.3,0.3,
- LOCALVIEWER, 0.0,
- LMNULL
- };
-
- static float white_light[] = {
- AMBIENT, 0.2, 0.2, 0.2,
- LCOLOR, 0.9, 0.9, 0.9,
- POSITION, 10.0,50.0,50.0,0.0,
- LMNULL
- };
-
- static Matrix iden = {1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0 };
-
- short ax, ay, az; /* angles for the "twirling" green sphere to ride on */
- long xsize, ysize; /* current size-of-window keepers */
- long zfar; /* used in czclear for the machine's zbuffer max */
- long buffermode; /* flag tracks current window (single or double) */
-
-
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- int myExpose, myConfigure,
- myButtRelease, myKeyPress; /* store which events occur */
-
-
-
- myExpose = myConfigure = myButtRelease = myKeyPress = FALSE;
-
- openwindow(argv[0]);
-
- /* initialize *both* windows just as we wud do with winopen/winset */
- Winset(wins[DBglwin], DBglwin);
- initGL(); /* do GL init stuff */
- setMatrix();
- bindLight();
-
- /* start out making the singlebuffer window be our current GL window */
- Winset(wins[SBglwin], SBglwin);
- initGL(); /* do GL init stuff */
- setMatrix();
- bindLight();
- drawScene(); /* and begin by drawing the scene in singlebuffer mode */
-
-
- /*
- * The event loop.
- */
- while (1) { /* standard logic: get event(s), process event(s) */
-
- XEvent event;
- KeySym keysym;
- char buf[4];
-
- gflush(); /* For proper DGL performance */
-
- /* this "do while" loop does the `get events' half of the "get events,
- * process events" action of the infinite while. this is to ensure
- * the event queue is always drained before the events that have come
- * in are processed.
- */
- do {
-
- XNextEvent(dpy, &event);
- printf("event %d\n", event.type);
- switch (event.type) {
-
-
- /* "Expose" events are sort of like "REDRAW" in gl-speak in
- * terms of when a window becomes visible, or a previously
- * invisible part becomes visible.
- */
- case Expose: /* Exposures */
- myExpose = TRUE;
- break;
-
-
- /* "ConfigNotify" events are like "REDRAW" in terms of changes
- * to a window's size or position.
- */
- case ConfigureNotify: /* Resize GL manually */
- if (event.xconfigure.window == wins[top]) {
- /* save the changed width/height of the parent X window */
- xsize = event.xconfigure.width;
- ysize = event.xconfigure.height;
- myConfigure = TRUE;
- }
- break;
-
-
- /* Wait for "ButtonRelease" events so the queue doesn't fill up
- * the way it wud if the user sits on ButtonPresss.
- */
- case ButtonRelease:
- if (event.xbutton.button == Button1) { /* LEFTMOUSE: */
- buffermode = SBglwin; /* switch to */
- myButtRelease = TRUE; /* singlebuffer*/
- } else if (event.xbutton.button == Button2) {
- buffermode = DBglwin; /* MIDDLEMOUSE: switch */
- myButtRelease = TRUE; /* to doublebuffer mode */
- } else if (event.xbutton.button == Button3) {
- loop(); /* RIGHTMOUSE: */
- } /* twirl the green sphere */
- break;
-
-
- /* "ClientMessage" is generated if the WM itself is being
- * gunned down and sends an exit signal to any running prog.
- */
- case ClientMessage:
- if (event.xclient.data.l[0] == del_atom)
- clean_exit();
- break;
-
-
- /* "KeyPress" events are those that would be generated before
- * whenever queueing up any KEYBD key via qdevice.
- */
- case KeyPress:
- /* save out which unmodified key (i.e. the key was
- * not modified w/something like "Shift", "Ctrl",
- * or "Alt") got pressed for use below.
- */
- XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
- myKeyPress = TRUE;
- break;
-
- } /* end switch (event.type) */
-
-
- } while (XPending(dpy)); /* end "do { } while".
- * XPending() is like qtest()--it only
- * tells you if there're any events
- * presently in the queue. it does not
- * disturb queue's contents in any way.
- */
-
- /* On an "Expose" event, redraw the affected pop'd or de-iconized window
- */
- if (myExpose) {
- drawScene(); /* draw the GL stuff */
- myExpose = FALSE; /* reset flag--queue now empty */
- }
-
- /* On a "ConfigureNotify" event, the GL window has either been moved or
- * resized. Respond accordingly and then redraw its contents.
- */
- if (myConfigure) {
- if (buffermode == SBglwin) {
- resize_buffer(DBglwin); /* update viewport & CTM stuff */
- resize_buffer(SBglwin); /* for *both* windows and then */
- bindLight(); /* bind the light to current 1 */
- } else if (buffermode == DBglwin) {
- resize_buffer(SBglwin);
- resize_buffer(DBglwin);
- bindLight();
- }
- drawScene();
- myConfigure = FALSE; /* reset flag--queue now empty */
- }
-
- /* On a "ButtonRelease" event, the flag gets set only for the LEFTMORE
- * or MIDDLEMOUSE. we need to change the buffermode state in this case.
- * In either case, XStoreName updates the window's title bar, Winset
- * then switches to the current buffermode graphics context, and we
- * Map the current window *BEFORE* we unmap the previous one. this
- * alleviates a painful "flicker" that occurs if you unmap the previous
- * window first.
- */
- if (myButtRelease) {
- if (buffermode == SBglwin) {
- XStoreName(dpy,wins[top],"single[LEFTMOUSE]-buffer GL window");
- Winset(wins[SBglwin], SBglwin);
- XMapWindow(dpy, wins[SBglwin]);
- XUnmapWindow(dpy, wins[DBglwin]);
- } else if (buffermode == DBglwin) {
- XStoreName(dpy,wins[top],"double[RIGHTMOUSE]-buffer GL window");
- Winset(wins[DBglwin], DBglwin);
- XMapWindow(dpy, wins[DBglwin]);
- XUnmapWindow(dpy, wins[SBglwin]);
- }
- myButtRelease = FALSE;
- }
-
- /* On a keypress of Esc key, exit program.
- */
- if (myKeyPress) {
- if (keysym == XK_Escape)
- clean_exit();
- }
-
- } /* end while(1) */
-
- }
-
-
-
- /* openwindow -
- * establish connection to X server, get screen info, specify the
- * attributes we want the WM to try to provide, and create the 2
- * GL windows--one single and one double -buffered--that we'll employ.
- */
- static void openwindow(char *progname) {
-
- int scrnnum; /* X screen number */
- int xorig, yorig; /* window (upper-left) origin */
- long scrnheight;
- XSizeHints Winhints; /* used to fix window size */
- XSetWindowAttributes swa;
- XColor gray;
-
-
-
- /* Connect to the X server and get screen info */
- if ((dpy = XOpenDisplay(NULL)) == NULL) {
- fprintf(stderr, "%s: cannot connect to X server %s\n",
- progname, XDisplayName(NULL));
- exit(1);
- }
- scrnnum = DefaultScreen(dpy);
- scrnheight = DisplayHeight(dpy, scrnnum);
-
- /* define window initial size */
- xorig = 50; yorig = 50;
- xsize = 300; ysize = 300;
-
- /* first create the top level X window. */
- wins[top] = XCreateSimpleWindow(dpy, RootWindow(dpy, scrnnum),
- xorig, yorig, xsize, ysize, 0, 0, 0);
- if (!(wins[top])) {
- fprintf(stderr,"%s: couldn't create \"parent\" X window\n",progname);
- exit(1);
- }
-
- /* define string that will show up in the window title bar (and icon) */
- XStoreName(dpy,wins[top],"single/double -buffer program");
-
- /* specify the values for the Window Size Hints we want to enforce: this
- * window's aspect ratio needs to stay at 1:1, constrain min and max
- * window size, and specify the initial size of the window.
- */
- Winhints.width = xsize; /* specify desired x/y size of window */
- Winhints.height = ysize;
- Winhints.min_width = xsize; /* define min and max */
- Winhints.max_width = scrnheight-1; /* width and height */
- Winhints.min_height = ysize;
- Winhints.max_height = scrnheight-1;
- Winhints.min_aspect.x = 1; /* keep aspect at a 1:1 ratio */
- Winhints.max_aspect.x = 1;
- Winhints.min_aspect.y = 1;
- Winhints.max_aspect.y = 1;
- /* set the corresponding flags */
- Winhints.flags = USSize|PMaxSize|PMinSize|PAspect;
- XSetNormalHints(dpy, wins[top], &Winhints);
-
-
- /* create a singlebuffer GL imaging window */
- if ((wins[SBglwin] = glx_create_window(wins[top], 0, 0, xsize, ysize,
- SBglwin, progname)) == NULL) {
- fprintf(stderr,"%s: couldn't create singlebuffer GL window\n",progname);
- exit(1);
- }
-
- /* create a doublebuffer GL imaging window */
- if ((wins[DBglwin] = glx_create_window(wins[top], 0, 0, xsize, ysize,
- DBglwin, progname)) == NULL) {
- fprintf(stderr,"%s: couldn't create doublebuffer GL window\n",progname);
- exit(1);
- }
-
- /* express interest in certain events */
- XSelectInput(dpy, wins[top], StructureNotifyMask | ButtonPressMask |
- KeyPressMask | ButtonReleaseMask);
- XSelectInput(dpy, wins[SBglwin], StructureNotifyMask|ExposureMask);
- XSelectInput(dpy, wins[DBglwin], StructureNotifyMask|ExposureMask);
-
- /* express interest in WM killing this app */
- if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", True)) != None)
- XSetWMProtocols(dpy, wins[top], &del_atom, 1);
-
- /* ensure the GL colormap is installed for this app */
- XSetWMColormapWindows(dpy, wins[top], wins, WINMAX);
-
- /* map the singlebuffer window to start up with */
- XMapWindow(dpy, wins[SBglwin]);
- XMapWindow(dpy, wins[top]);
- }
-
-
- char *typeToName[] = {
- "RGB single buffer",
- "RGB double buffer",
- };
-
-
- /* A little helper wrapper for GLXwinset.
- * It passes the global variable "dpy" which contains the display, and it
- * checks the return value. This makes the call to begin GL drawing a
- * little simpler. Building in such automatic error checking is always a
- * "smooth move" (*not* like the cancerously-mutant human with the big
- * proboscis who is plastered all over the place urging people to be
- * likewise smoothly cancerous and hardly cool...).
- */
- void Winset(Window w, int type)
- {
- int rv = GLXwinset(dpy, w);
- if (rv < 0) {
- fprintf(stderr, "GLXWinset returned %d\ for the %s window\n",
- rv, typeToName[type-1]);
- exit(-1);
- }
- }
-
- /* Dorky little helper function used to build up a GLXconfig array.
- */
- static void set_entry (GLXconfig* ptr, int b, int m, int a)
- {
- ptr->buffer = b;
- ptr->mode = m;
- ptr->arg = a;
- }
-
-
- /* glx_create_window -- Create a single or a double -buffered, colorindex
- * X window suitable for GL imaging.
- *
- * Parameters: parent - parent window for the GL imaging window
- * x, y - window origin relative to parent
- * w, h - window width and height
- * type - single or double -buffer specifier
- * progname - name of executable
- */
- static Window glx_create_window(Window parent, int x, int y, int w, int h,
- int type, char *progname)
- {
- GLXconfig params[50];
- GLXconfig *next, *retconfig;
- Colormap cmap = DefaultColormap(dpy, DefaultScreen(dpy));
- XVisualInfo* vis;
- XVisualInfo template;
- XSetWindowAttributes cwa;
- XWindowAttributes pwa;
- int i, nret;
- Window win;
-
-
-
- /* first build an array in "params" that describes for GLXgetconfig(3G)
- * the type of GL drawing that will be done.
- */
- next = params;
- switch (type) {
- case SBglwin:
- set_entry(next++, GLX_NORMAL, GLX_DOUBLE, FALSE);
- set_entry(next++, GLX_NORMAL, GLX_RGB, TRUE);
- set_entry(next++, GLX_NORMAL, GLX_ZSIZE, GLX_NOCONFIG);
- break;
- case DBglwin:
- set_entry(next++, GLX_NORMAL, GLX_DOUBLE, TRUE);
- set_entry(next++, GLX_NORMAL, GLX_RGB, TRUE);
- set_entry(next++, GLX_NORMAL, GLX_ZSIZE, GLX_NOCONFIG);
- break;
- }
- set_entry(next, 0, 0, 0); /* The input to GLXgetconfig is null terminated */
-
- /*
- * Get configuration data for a window based on above parameters.
- * First we have to find out which screen the parent window is on,
- * then we can call GXLgetconfig()
- */
- XGetWindowAttributes(dpy, parent, &pwa);
- retconfig = GLXgetconfig(dpy, XScreenNumberOfScreen(pwa.screen), params);
- if (retconfig == 0) {
- printf("Sorry, can't support %s type of windows\n", typeToName[type-1]);
- exit(-1);
- }
- /*
- * The GL sets its own X error handlers, which aren't as informative
- * when errors happen. Calling XSetErrorHandler(0) here will
- * reset back to the default Xlib version.
- */
- XSetErrorHandler(0);
-
- /*
- * Scan through config info, pulling info we need to create a window
- * that supports the rendering mode.
- */
- for (next = retconfig; next->buffer; next++) {
- unsigned long buffer = next->buffer;
- unsigned long mode = next->mode;
- unsigned long value = next->arg;
- switch (mode) {
- case GLX_COLORMAP:
- if (buffer == GLX_NORMAL) {
- cmap = value;
- }
- break;
- case GLX_VISUAL:
- if (buffer == GLX_NORMAL) {
- template.visualid = value;
- template.screen = DefaultScreen(dpy);
- vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask,
- &template, &nret);
- }
- break;
- }
- }
-
- /* Create the window */
- cwa.colormap = cmap;
- cwa.border_pixel = 0;
- win = XCreateWindow(dpy,parent,x,y,w,h,0,vis->depth,
- InputOutput,vis->visual,CWColormap|CWBorderPixel,&cwa);
- /*
- * now rescan configuration info, find the window slot GLXgetconfig
- * provided and fill it in with the window we just created.
- */
- for (next = retconfig; next->buffer; next++) {
- if ((next->buffer == GLX_NORMAL) && (next->mode == GLX_WINDOW)) {
- next->arg = win;
- break;
- }
- }
-
- /* link to the GL */
- if ((i = GLXlink(dpy, retconfig)) < 0) {
- fprintf(stderr, "GLXlink returned %d for the %s window\n",
- i, typeToName[type-1]);
- exit(-1);
- }
-
- return win;
- }
-
-
-
- /* window has been moved or resized so update viewport & CTM stuff.
- */
- static void resize_buffer(long wintype) {
-
- XMoveResizeWindow(dpy, wins[wintype], 0, 0, xsize, ysize);
- XSync(dpy, False); /* Need before GL reshape */
- Winset(wins[wintype],wintype);
- viewport(0, (short) (xsize - 1), 0, (short) (ysize - 1));
- setMatrix();
- }
-
-
-
- /* clean up before exiting
- */
- static void clean_exit(void)
- {
- XCloseDisplay(dpy);
- exit(0);
- }
-
-
- /* setup all necessary GL initialzation parameters.
- */
- void
- initGL()
- {
- zbuffer(TRUE);
-
- lmdef(DEFMATERIAL,1,11,material1);
- lmdef(DEFMATERIAL,2,11,material2);
- lmdef(DEFLIGHT, 1,14,white_light);
- lmdef(DEFLMODEL, 1,7,infinite);
-
- lsetdepth(getgdesc(GD_ZMIN),getgdesc(GD_ZMAX));
- shademodel(GOURAUD);
- sphmode(SPH_PRIM,SPH_MESH);
- sphmode(SPH_DEPTH,8);
- buffermode = SBglwin;
- zfar = getgdesc(GD_ZMAX);
- }
-
-
- /* define our Current Transformation Matrix
- */
- void
- setMatrix()
- {
- mmode(MPROJECTION);
- ortho(-10.0,10.0,-10.0,10.0,-10.0,10.0);
- mmode(MVIEWING);
- loadmatrix(iden);
- lookat(0.0,0.0,3.0,0.0,0.0,0.0,0);
- }
-
-
- /* update the lighting model
- */
- void
- bindLight()
- {
- pushmatrix();
- loadmatrix(iden);
- lmbind(LIGHT0,1);
- lmbind(LMODEL,1);
- popmatrix();
- }
-
-
- /* draw our two spheres
- */
- void
- drawScene()
- {
- static float sp1[] = {0.2,0.2,0.2,3.0};
- static float sp2[] = {3.4,3.4,0.2,4.0};
-
- czclear(BLACK, zfar);
-
- pushmatrix();
- lmbind(MATERIAL,1);
- sphdraw(sp1);
- rotate(ax,'x');
- rotate(ay,'y');
- rotate(az,'z');
- lmbind(MATERIAL,2);
- sphdraw(sp2);
- popmatrix();
-
- if (buffermode == DBglwin)
- swapbuffers();
- }
-
-
- /* perform one loop of twirling the green sphere
- */
- void
- loop()
- {
- register int i;
-
- for (i=0;i<50;i++) {
- ax += 50;
- ay -= 25;
- az += 50;
- if (ax >= 3600) ax = 0;
- if (ay <= -3600) ay = 0;
- if (az >= 3600) az = 0;
- drawScene();
- }
- }
-